前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
AI 面试
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
AI 面试
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
  • React专栏

    • React组合式开发实战

      • 前端开发的四个时代
      • 企业管理系统的前世今生
      • 可视化页面搭建工具
      • 实战篇 01:开发前准备
      • 实战篇 02:项目脚手架
      • 实战篇 03:页面布局方案
      • 实战篇 04:权限管理机制
      • 实战篇 05:菜单匹配逻辑
      • 实战篇 06:消息通知设计
      • 实战篇 07:多语言支持
      • 继往开来:可视化页面搭建工具
    • React Hooks与Immutable实战

    • React SSR服务端渲染与同构实践

    • IM聊天系统前端开发实践

    • 微前端开发实战

    • React进阶实践

  • Vue专栏

  • 移动端专栏

  • Node专栏

  • 前端工程化专栏

  • 算法专栏

  • Typescript专栏

  • 其他专栏

完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

代码 parse 成 AST 之后,可以对 AST 进行 transform,然后 generate 成目标代码,这是转译器(transpiler)的流程,也可以对 AST 进行解释执行,这是解释器(interpreter)的流程。这一节,我们来基于 babel parser 来实现一个简单的 js 解释器。

# v8 的编译流水线

v8 包括 4 部分,parser、ignation 解释器,JIT 编译器,还有 garbage collector(垃圾回收器)。

  • parser 负责把源码 parse 成 AST。
  • ignation 解释器负责把 AST 转成字节码,然后解释执行
  • turbofan 可以把代码编译成机器码,直接执行
  • gc 负责堆内存的垃圾回收

image.png

其实最早期的 v8 是没有字节码的,就是直接解释执行 AST:

image.png

这种直接解释执行 AST 的解释器叫做 tree walker 解释器,这一节,我们来实现一下这种 js 解释器。

# 实现 JS 解释器

# 思路分析

当 parser 把 源码 parse 成 AST 之后,其实已经能够拿到源码的各部分信息了,比如

const a = 1 + 2;
@前端进阶之旅: 代码已经复制到剪贴板

对应的 AST 是这样的

image.png

当我们处理到 BinarayExpression 节点,operator 是 +,会做加法运算,取左右两边的值相加。

当我们处理到 NumercLiteral 节点,是数字字面量,直接返回它的值(value)。

当我们处理到 Identifier 节点,是标识符,直接返回名字(name)。

当我们处理到 VariableDeclarator,我们就知道是一个变量声明语句,要在作用域 (scope)中放一个属性,属性名为 id 的值, 属性值为 init 的值。而 id 和 init 可以求出来。

就这样,我们就完成了这段代码的解释执行。

# 代码实现

先搭一个基本的结构:

const  parser = require('@babel/parser');
const { codeFrameColumns } = require('@babel/code-frame');

const sourceCode = `
   const a = 1 + 2;
`;

const ast = parser.parse(sourceCode, {
    sourceType: 'unambiguous'
});

const evaluator = (function() {

    const astInterpreters = {
        Program (node, scope) {
            node.body.forEach(item => {
                evaluate(item, scope);
            })
        }
    }

    const evaluate = (node, scope) => {
        try {
            return astInterpreters[node.type](node, scope);
        } catch(e) {
            if (e && e.message && e.message.indexOf('astInterpreters[node.type] is not a function') != -1) {
                console.error('unsupported ast type: ' + node.type);
                console.error(codeFrameColumns(sourceCode, node.loc, {
                    highlightCode: true
                }));
            } else {
                
fe
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
AI 面试
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
  • React专栏

    • React组合式开发实战

      • 前端开发的四个时代
      • 企业管理系统的前世今生
      • 可视化页面搭建工具
      • 实战篇 01:开发前准备
      • 实战篇 02:项目脚手架
      • 实战篇 03:页面布局方案
      • 实战篇 04:权限管理机制
      • 实战篇 05:菜单匹配逻辑
      • 实战篇 06:消息通知设计
      • 实战篇 07:多语言支持
      • 继往开来:可视化页面搭建工具
    • React Hooks与Immutable实战

    • React SSR服务端渲染与同构实践

    • IM聊天系统前端开发实践

    • 微前端开发实战

    • React进阶实践

  • Vue专栏

  • 移动端专栏

  • Node专栏

  • 前端工程化专栏

  • 算法专栏

  • Typescript专栏

  • 其他专栏